home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
United Public Domain Gold 4
/
United Public Domain Gold 4.iso
/
fredfish
/
ff.0010.dms
/
ff.0010.adf
/
iff
/
readpict.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-02-02
|
11KB
|
289 lines
/** ReadPict.c **************************************************************
*
* Read an ILBM raster image file. 01/07/85.
*
* By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
* This software is in the public domain.
*
* USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF READER.
*
* The IFF reader portion is essentially a recursive-descent parser.
* This program will look into a CAT or LIST to find a FORM ILBM, but it
* won't look inside another FORM type for a nested FORM ILBM.
****************************************************************************/
#define LOCAL /* static */
/* #include "intuall.h" */
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include "ilbm.h"
#include "readpict.h"
/* This example's max number of planes in a bitmap. Could use MaxAmDepth. */
#define EXDepth 5
#define maxColorReg (1<<EXDepth)
#define MIN(a,b) ((a)<(b)?(a):(b))
#define SafeFreeMem(p,q) {if(p)FreeMem(p,q);}
/* Define the size of a temporary buffer used in unscrambling the ILBM rows.*/
#define bufSz 512
/*------------- External functions for Manx --------------*/
extern IFFP OpenRGroup();
extern IFFP GetFChunkHdr();
/*------------ ILBM reader -----------------------------------------------*/
/* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file.
* We allocate one of these on the stack for every LIST or FORM encountered
* in the file and use it to hold BMHD & CMAP properties. We also allocate
* an initial one for the whole file.
* We allocate a new GroupContext (and initialize it by OpenRIFF or
* OpenRGroup) for every group (FORM, CAT, LIST, or PROP) encountered. It's
* just a context for reading (nested) chunks.
*
* If we were to scan the entire example file outlined below:
* reading proc(s) new new
*
* --whole file-- ReadPicture+ReadIFF GroupContext ILBMFrame
* CAT ReadICat GroupContext
* LIST GetLiILBM+ReadIList GroupContext ILBMFrame
* PROP ILBM GetPrILBM GroupContext
* CMAP GetCMAP
* BMHD GetBMHD
* FORM ILBM GetFoILBM GroupContext ILBMFrame
* BODY GetBODY
* FORM ILBM GetFoILBM GroupContext ILBMFrame
* BODY GetBODY
* FORM ILBM GetFoILBM GroupContext ILBMFrame
*/
/* NOTE: For a simple version of this program, set Fancy to 0.
* That'll compile a program that skips all LISTs and PROPs in the input
* file. It will look in CATs for FORMs ILBM. That's suitable for most uses.
*
* For a fancy version that handles LISTs and PROPs, set Fancy to 1. */
#define Fancy 0
/* Global access to client-provided pointers.*/
LOCAL UBYTE *(*gAllocator)() = NL; /* $$$ changed from NULL */
/* Allocator which only needs size parameter.*/
LOCAL struct BitMap *gBM = NL; /* client's bitmap.*/
LOCAL ILBMFrame *giFrame = NL; /* "client frame".*/
/** GetFoILBM() *************************************************************
*
* Called via ReadPicture to handle every FORM encountered in an IFF file.
* Reads FORMs ILBM and skips all others.
* Inside a FORM ILBM, it stops once it reads a BODY. It complains if it
* finds no BODY or if it has no BMHD to decode the BODY.
*
* Once we find a BODY chunk, we'll allocate the BitMap and read the image.
*
****************************************************************************/
LOCAL BYTE bodyBuffer[bufSz];
IFFP GetFoILBM(parent)
GroupContext *parent;
{
/*compilerBug register*/ IFFP iffp;
GroupContext formContext;
ILBMFrame ilbmFrame; /* only used for non-clientFrame fields.*/
register int i;
long plsize; /* Plane size in bytes. */
long nPlanes; /* number of planes in our display image */
if (parent->subtype != ID_ILBM)
return(IFF_OKAY); /* just continue scaning the file */
ilbmFrame = *(ILBMFrame *)parent->clientFrame;
iffp = OpenRGroup(parent, &formContext);
CheckIFFP();
do {
iffp = GetFChunkHdr(&formContext);
if (iffp == ID_BMHD) {
ilbmFrame.foundBMHD = TRUE;
iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr);
}
else if (iffp == ID_CMAP) {
ilbmFrame.nColorRegs = maxColorReg; /* we have room for this many */
iffp = GetCMAP(
&formContext, (WORD *)&ilbmFrame.colorMap, &ilbmFrame.nColorRegs);
}
else if (iffp == ID_BODY) {
if (!ilbmFrame.foundBMHD) return(BAD_FORM); /* No BMHD chunk! */
nPlanes = MIN(ilbmFrame.bmHdr.nPlanes, EXDepth);
InitBitMap(
gBM,
nPlanes,
(long)ilbmFrame.bmHdr.w,
(long)ilbmFrame.bmHdr.h);
plsize = RowBytes(ilbmFrame.bmHdr.w) * ilbmFrame.bmHdr.h;
/* Allocate all planes contiguously. Not really necessary,
* but it avoids writing code to back-out if only enough memory
* for some of the planes.
* WARNING: Don't change this without changing the code that
* Frees these planes.
*/
if (gBM->Planes[0] =
(PLANEPTR)(*gAllocator)(nPlanes * plsize))
{
for (i = 1; i < nPlanes; i++)
gBM->Planes[i] = (PLANEPTR) gBM->Planes[0] + plsize*i;
iffp = GetBODY(
&formContext,
gBM,
NULL,
&ilbmFrame.bmHdr,
bodyBuffer,
(long)bufSz);
if (iffp == IFF_OKAY) iffp = IFF_DONE; /* Eureka */
*giFrame = ilbmFrame; /* Copy fields to client's frame.*/
}
else
iffp = CLIENT_ERROR; /* not enough RAM for the bitmap */
}
else if (iffp == END_MARK)
iffp = BAD_FORM;
} while (iffp >= IFF_OKAY); /* loop if valid ID of ignored chunk or a
* subroutine returned IFF_OKAY (no errors).*/
if (iffp != IFF_DONE) return(iffp);
/* If we get this far, there were no errors. */
CloseRGroup(&formContext);
return(iffp);
}
/** Notes on extending GetFoILBM ********************************************
*
* To read more kinds of chunks, just add clauses to the switch statement.
* To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to
* the switch statement in GetPrILBM, too.
*
* To read a FORM type that contains a variable number of data chunks--e.g.
* a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with
* an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK
* case do whatever cleanup you need.
*
****************************************************************************/
/** GetPrILBM() *************************************************************
*
* Called via ReadPicture to handle every PROP encountered in an IFF file.
* Reads PROPs ILBM and skips all others.
*
****************************************************************************/
#if Fancy
IFFP GetPrILBM(parent)
GroupContext *parent;
{
/*compilerBug register*/ IFFP iffp;
GroupContext propContext;
ILBMFrame *ilbmFrame = (ILBMFrame *)parent->clientFrame;
if (parent->subtype != ID_ILBM)
return(IFF_OKAY); /* just continue scaning the file */
iffp = OpenRGroup(parent, &propContext);
CheckIFFP();
do switch (iffp = GetPChunkHdr(&propContext)) {
case ID_BMHD: {
ilbmFrame->foundBMHD = TRUE;
iffp = GetBMHD(&propContext, &ilbmFrame->bmHdr);
break; }
case ID_CMAP: {
ilbmFrame->nColorRegs = maxColorReg; /* we have room for this many */
iffp = GetCMAP(
&propContext, (WORD *)&ilbmFrame->colorMap, &ilbmFrame->nColorRegs);
break; }
} while (iffp >= IFF_OKAY); /* loop if valid ID of ignored chunk or a
* subroutine returned IFF_OKAY (no errors).*/
CloseRGroup(&propContext);
return(iffp == END_MARK ? IFF_OKAY : iffp);
}
#endif
/** GetLiILBM() *************************************************************
*
* Called via ReadPicture to handle every LIST encountered in an IFF file.
*
****************************************************************************/
#if Fancy
IFFP GetLiILBM(parent) GroupContext *parent; {
ILBMFrame newFrame; /* allocate a new Frame */
newFrame = *(ILBMFrame *)parent->clientFrame; /* copy parent frame */
return( ReadIList(parent, (ClientFrame *)&newFrame) );
}
#endif
/** ReadPicture() ***********************************************************
*
* Read a picture from an IFF file, given a file handle open for reading.
* Allocates BitMap using (*Allocator)().
*
****************************************************************************/
IFFP ReadPicture(file, bm, iFrame, Allocator)
LONG file;
struct BitMap *bm;
ILBMFrame *iFrame; /* Top level "client frame".*/
UBYTE *(*Allocator)(); /* Allocation procedure which only requires
* size parameter. That is, no flags parameter.
* Must be in Chip memory, for bitmap data.*/
{
IFFP iffp = IFF_OKAY;
#if Fancy
iFrame->clientFrame.getList = GetLiILBM;
iFrame->clientFrame.getProp = GetPrILBM;
#else
iFrame->clientFrame.getList = SkipGroup;
iFrame->clientFrame.getProp = SkipGroup;
#endif
iFrame->clientFrame.getForm = GetFoILBM;
iFrame->clientFrame.getCat = ReadICat ;
/* Initialize the top-level client frame's property settings to the
* program-wide defaults. This example just records that we haven't read
* any BMHD property or CMAP color registers yet. For the color map, that
* means the default is to leave the machine's color registers alone.
* If you want to read a property like GRAB, init it here to (0, 0). */
iFrame->foundBMHD = FALSE;
iFrame->nColorRegs = 0;
gAllocator = Allocator;
gBM = bm;
giFrame = iFrame;
/* Store a pointer to the client's frame in a global variable so that
* GetFoILBM can update client's frame when done. Why do we have so
* many frames & frame pointers floating around causing confusion?
* Because IFF supports PROPs which apply to all FORMs in a LIST,
* unless a given FORM overrides some property.
* When you write code to read several FORMs,
* it is essential to maintain a frame at each level of the syntax
* so that the properties for the LIST don't get overwritten by any
* properties specified by individual FORMs.
* We decided it was best to put that complexity into this one-FORM example,
* so that those who need it later will have a useful starting place.
*/
iffp = ReadIFF(file, (ClientFrame *)iFrame);
return(iffp);
}